﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace App1
{
    public sealed partial class MainPage : Page
    {
        public MainPage() { this.InitializeComponent(); }
    }

    public class MyVarGridView : GridView
    {
        public MyVarGridView()
        {
           Loaded += MyGridView_Loaded;
        }

        class SubtractConverter : IValueConverter
        {
            public double Amount { get; set; }
            public object Convert(object v, Type t, object p, string l)
            { return System.Convert.ToDouble(v) - Amount; }
            public object ConvertBack(object v, Type t, object p, string l)
            { throw new NotImplementedException(); }
        }

        void MyGridView_Loaded(object sender, RoutedEventArgs args)
        {
            var converter = new SubtractConverter { Amount = 5 * 2 /* padding x2 */ };
            foreach (GroupItem group in (this.ItemsPanelRoot as Panel).Children)
            {
                var result = VisualTreeHelper.GetChild(group, 0);
                while (!(result is Grid))
                    result = VisualTreeHelper.GetChild(result, 0);
                var items = (result as Panel).Children.OfType<ItemsControl>()
                    .First().ItemsPanelRoot;
                var binding = new Binding
                {
                    Path = new PropertyPath("ActualWidth"),
                    Mode = BindingMode.OneWay,
                    Converter = converter,
                    Source = items,
                };
                var header = (result as Panel).Children.OfType<ContentControl>()
                    .First().ContentTemplateRoot as FrameworkElement;
                header.SetBinding(FrameworkElement.MaxWidthProperty, binding);
            }
        }

        protected override void PrepareContainerForItemOverride(Windows.UI.Xaml.DependencyObject element, object item)
        {
            try
            {
                dynamic dyn = item;
                element.SetValue(Windows.UI.Xaml.Controls.VariableSizedWrapGrid.ColumnSpanProperty, dyn.ColSpan);
                element.SetValue(Windows.UI.Xaml.Controls.VariableSizedWrapGrid.RowSpanProperty, dyn.RowSpan);
            }
            catch
            {
                element.SetValue(Windows.UI.Xaml.Controls.VariableSizedWrapGrid.ColumnSpanProperty, 1);
                element.SetValue(Windows.UI.Xaml.Controls.VariableSizedWrapGrid.RowSpanProperty, 1);
            }
            finally
            {
                base.PrepareContainerForItemOverride(element, item);
            }
        }
    }

    namespace ViewModels
    {
        using System.Collections.ObjectModel;
        using System.Reflection;

        class MainPageViewModel
        {
            public MainPageViewModel()
            {
                var colors = typeof(Windows.UI.Colors).GetRuntimeProperties()
                    .Select(x => new Models.ColorInfo
                    {
                        Name = x.Name,
                        Color = (Windows.UI.Color)x.GetValue(null),
                        ColSpan = 250,
                        RowSpan = 100,
                    });

                this.Groups.Clear();
                for (int i = 0; i < 3; i++)
                {
                    var group = new Models.GroupInfo
                    {
                        Name = "Group " + (i + 1).ToString(),
                        Children = colors.Skip(09 * i).Take(09).ToArray()
                    };
                    foreach (var item in group.Children.Where((x, d) => d % 4 == 0))
                        item.RowSpan = 300;
                    this.Groups.Add(group);
                }
            }

            ObservableCollection<Models.GroupInfo> _Groups
                = new ObservableCollection<Models.GroupInfo>();
            public ObservableCollection<Models.GroupInfo> Groups { get { return _Groups; } }
        }
    }

    namespace Models
    {
        class GroupInfo
        {
            public string Name { get; set; }
            public ColorInfo[] Children { get; set; }
        }

        class ColorInfo : Common.ModelBase
        {
            public string Name { get; set; }
            public Windows.UI.Color Color { get; set; }
            public Windows.UI.Xaml.Media.SolidColorBrush Brush { get { return new Windows.UI.Xaml.Media.SolidColorBrush(this.Color); } }
        }
    }

    namespace Common
    {
        abstract class ModelBase : Common.BindableBase
        {
            public int ColSpan { get; set; }
            public int RowSpan { get; set; }
        }

        abstract class BindableBase : System.ComponentModel.INotifyPropertyChanged
        {
            public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
            protected void SetProperty<T>(ref T storage, T value, [System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
            {
                if (!object.Equals(storage, value))
                {
                    storage = value;
                    if (PropertyChanged != null)
                        PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
                }
            }
            protected void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
            }
        }
    }
}
